package bot.config;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

/**
 * This class parses the configfile of the bot and generates a Hashmap of its configuration content.
 * 
 * @see bot.config.data.about_configuration.txt
 * @author Witthold/Korol
 */
public final class BotConfig {

	private static String configPath = "bin/bot/config/data/";

	private static Section section = null;

	private static HashMap<String, String> general;
	private static HashMap<String, String> server;
	private static HashMap<String, String> gamestorage;
	private static HashMap<String, String> startinghandchart;
	private static HashMap<String, String> potodds;
	private static HashMap<String, String> bluffing;
	private static HashMap<String, String> squeezing;
	private static HashMap<String, String> opponentrecognition;
	private static HashMap<String, String> ext_proposal;

	private static List<HashMap<String, String>> botConfig = new ArrayList<HashMap<String, String>>();

	/**
	 * Sections in configFile as enums
	 *
	 */
	public enum Section {
		GENERAL {
			void processTokens(String line) {
				processMyTokens(general, line);
			}
		},
		SERVER {
			void processTokens(String line) {
				processMyTokens(server, line);
			}
		},
		GAMESTORAGE {
			void processTokens(String line) {
				processMyTokens(gamestorage, line);
			}
		},
		STARTINGHANDCHART {
			void processTokens(String line) {
				processMyTokens(startinghandchart, line);
			}
		},
		POTODDS {
			void processTokens(String line) {
				processMyTokens(potodds, line);
			}
		},
		BLUFFING {
			void processTokens(String line) {
				processMyTokens(bluffing, line);
			}
		},
		SQUEEZING {
			void processTokens(String line) {
				processMyTokens(squeezing, line);
			}
		},
		OPPONENTRECOGNITION {
			void processTokens(String line) {
				processMyTokens(opponentrecognition, line);
			}
		},
		EXT_PROPOSAL {
			void processTokens(String line) {
				processMyTokens(ext_proposal, line);
			}
		};

		abstract void processTokens(String line);
	}


	/**
	 * Parses config file
	 * 
	 * @param configFile
	 * @throws FileNotFoundException
	 */
	private final static void readConfig(File configFile) throws FileNotFoundException {

		Scanner scanner = new Scanner(configFile);
		try {
			/* use a Scanner to get each line */
			while (scanner.hasNextLine()) {
				String line = scanner.nextLine();
				if (line.startsWith("#") || line.isEmpty()) {
					continue;
				}
				//				DebugOut.showVerboseBot(line);
				processLine(line);
			}
		} finally {
			// ensure the underlying stream is always closed
			scanner.close();
		}
	}


	/**
	 * Parses one line; distinguishes, if line starts a new section or is content of one already initialized
	 * 
	 * @param String line in configFile
	 */
	private static void processLine(String line) {

		if (line.startsWith("[")) {
			section = initSection(line);
		} else if (section != null) { /* data now */
			section.processTokens(line);
		} else { /* section is null - something went wrong */
			System.err.println("Error: Section is null!");
		}
	}


	/**
	 * Initializes a section
	 * 
	 * @param String line in configFile
	 * @return specific Section
	 */
	private static Section initSection(String line) {
		if (line.startsWith("[GENERAL]")) {
			general = new HashMap<String, String>();
			botConfig.add((HashMap<String, String>) general);
			return Section.GENERAL;
		} else if (line.startsWith("[SERVER]")) {
			server = new HashMap<String, String>();
			botConfig.add(server);
			return Section.SERVER;
		} else if (line.startsWith("[GAMESTORAGE]")) {
			gamestorage = new HashMap<String, String>();
			botConfig.add(gamestorage);
			return Section.GAMESTORAGE;
		} else if (line.startsWith("[STARTINGHANDCHART]")) {
			startinghandchart = new HashMap<String, String>();
			botConfig.add(startinghandchart);
			return Section.STARTINGHANDCHART;
		} else if (line.startsWith("[POTODDS]")) {
			potodds = new HashMap<String, String>();
			botConfig.add(potodds);
			return Section.POTODDS;
		} else if (line.startsWith("[BLUFFING]")) {
			bluffing = new HashMap<String, String>();
			botConfig.add(bluffing);
			return Section.BLUFFING;
		} else if (line.startsWith("[SQUEEZING]")) {
			squeezing = new HashMap<String, String>();
			botConfig.add(squeezing);
			return Section.SQUEEZING;
		} else if (line.startsWith("[OPPONENTRECOGNITION]")) {
			opponentrecognition = new HashMap<String, String>();
			botConfig.add(opponentrecognition);
			return Section.OPPONENTRECOGNITION;
		} else if (line.startsWith("[EXT_PROPOSAL]")) {
			ext_proposal = new HashMap<String, String>();
			botConfig.add(ext_proposal);
			return Section.EXT_PROPOSAL;
		} else {
			return null;
		}
	}


	/**
	 * Fills the Hashmap with content
	 * 
	 * @param map
	 * @param line
	 */
	private static void processMyTokens(Map<String, String> map, String line) {

		if (map.isEmpty()) {
			map.put("Section", section.toString());
		}
		Scanner scanner = new Scanner(line);
		scanner.useDelimiter("=");
		if (scanner.hasNext()) {
			String name = scanner.next();
			String value = scanner.next();
			map.put(name, value);
		} else {
			System.err.println("ERROR: BotConfig: Unable to processMyTokens.");
		}
		scanner.close();
	}


	/**
	 * Cleans up the Hashmap from empty or not activated sections
	 * 
	 * @return botConfig - filled only with activated sections or GENERAL
	 */
	private static List<HashMap<String, String>> cleanUpBotConfig() {

		List<HashMap<String, String>> botConfigTmp = new ArrayList<HashMap<String, String>>();

		for (HashMap<String, String> section : botConfig) {

			if (section.containsKey("use") && section.get("use").equals("true") || section.get("Section").equals("GENERAL")
					|| section.get("Section").equals("SERVER")) {
				botConfigTmp.add(section);
			}
		}

		return botConfigTmp;
	}


	/**
	 * Triggers the whole process of parsing, processing and converting the txt-file into a Hashmaps
	 * 
	 * @param configName -
	 * @return the botConfig as ArrayList<HashMap<String, String>>
	 * @throws FileNotFoundException - 
	 */
	public static List<HashMap<String, String>> getBotConfig(String configName) throws FileNotFoundException {

		File configFile = new File(configPath + configName);
		readConfig(configFile);

		botConfig = cleanUpBotConfig();

		return botConfig;
	}

}
